use axum::{
    routing::{get,post},
    Router,
    extract::{Json,extractor_middleware},
    
};
use axum::extract::{ContentLengthLimit, Multipart, Query};
use axum::http::StatusCode;
use axum::routing::get_service;
use headers::HeaderMap;

use serde::{Serialize, Deserialize};
use tower_cookies::{CookieManagerLayer,Cookie,Cookies};
use tower_http::services::ServeDir;

use back_server2::{models::*, utils::auth::Auth,routers};
use uuid::Uuid;
use back_server2::utils;
use back_server2::utils::cookie;

#[derive(Serialize)]
pub struct MyResponce {
    pub status: String,
    pub discription: String,
    pub result: String,
}
#[tokio::main]
async fn main() {

    let protected_router = routers::protected::router()
        .layer(extractor_middleware::<Auth>());

    let guide_router = routers::guide::router();
    let communication_router = routers::communication::router();
    let module_recom_router = routers::module_recom::router();
    let image_share_router = routers::image_share::router();
    

    let app = Router::new()
        .route("/", get(|| async {
            "Hello World!"
        }))
        .nest("/protected", protected_router)
        .route("/login", post(login_action))
        .route("/logout",get(logout_action))
        .route("/reset_password", post(reset_password))
        .route("/reset_email", post(reset_email))
        .route("/reset_phone_number", post(reset_phone_number))
        .route("/reset_nickname", post(reset_nickname))
        .route("/reset_portrait", post(reset_portrait))
        .layer(CookieManagerLayer::new())
        .route("/register", post(register_action))

        .nest("/guide", guide_router)
        .nest("/communication", communication_router)
        .nest("/module_recom", module_recom_router)
        .nest("/image_share", image_share_router)

        .nest("/static",
              get_service(ServeDir::new("static")).handle_error(|error: std::io::Error| async move {
                  (
                      StatusCode::INTERNAL_SERVER_ERROR,
                      format!("Unhandled internal error: {}", error),
                  )
              }),
        )
        .route("/upload",post(accept_form))
        .route("/get_all_comments",get(get_all_comments))
        .route("/forbid_comment",get(forbid_comment))
        .route("/prime_comment",get(prime_comment))
        .route("/active_comment",get(active_comment))
        ;
    
    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
    .serve(app.into_make_service())
    .await
    .unwrap();
}

#[derive(Serialize,Deserialize,Debug)]
struct ChangeCommentStatus{
    comment_id:i32
}

async fn get_all_comments() -> Json<Vec<Comment>> {
    let comments = Comment::fetch_all().await.unwrap();
    Json(comments)
}

async fn forbid_comment(Query(query):Query<ChangeCommentStatus>) -> Json<bool> {
    if let Ok(_) = Comment::forbid_comment_by_id(query.comment_id).await{
        return Json(true)
    }
    Json(false)
}
async fn prime_comment(Query(query):Query<ChangeCommentStatus>) -> Json<bool> {
    if let Ok(_) = Comment::prime_comment_by_id(query.comment_id).await{
        return Json(true)
    }
    Json(false)
}
async fn active_comment(Query(query):Query<ChangeCommentStatus>) -> Json<bool> {
    if let Ok(_) = Comment::active_comment_by_id(query.comment_id).await{
        return Json(true)
    }
    Json(false)
}


#[derive(Serialize,Deserialize,Debug)]
struct UploadResponse{
    status: String,
    url: String,
    description:String,
}
async fn accept_form(
    ContentLengthLimit(mut multipart): ContentLengthLimit<
        Multipart,
        {
            250 * 1024 * 1024 /* 250mb */
        },
    >,
) ->  Json<UploadResponse> {


    if let Some(field) = multipart.next_field().await.unwrap() {
        // let name = field.name().unwrap().to_string();
        let file_name = field.file_name().unwrap().to_string();
        // let content_type = field.content_type().unwrap().to_string();
        let data = field.bytes().await.unwrap();
        let upload_path = format!("static/{}",file_name);
        if let Err(err) = tokio::fs::write(&upload_path, &data)
            .await
            .map_err(|err| err.to_string()){
            let res = UploadResponse{
                status:"bad".to_string(),
                url: "".to_string(),
                description: "上传失败！".to_string()
            };
            return Json(res);
        }else {
            let res = UploadResponse{
                status:"ok".to_string(),
                url: file_name.clone(),
                description: "上传成功！".to_string()
            };
            return Json(res)
        }

    }

    let res = UploadResponse{
        status:"bad".to_string(),
        url: "".to_string(),
        description: "上传失败！".to_string()
    };
    Json(res)
}

async fn register_action(Json(user): Json<CreateUser>) -> Json<MyResponce> {
    let res = User::insert(user.nickname, user.email, user.phone_number, user.password, vec![]).await;
    // let res = pg::insert_into_user(user).await;

    match res{
        Ok(res) => {
            Json(MyResponce{
                status: "Ok".to_string(),
                discription: "注册成功！".to_string(),
                result: res.to_string()
            })
            // Json(serde_json::json!({
            //     "status": "Ok",
            //     "discription":"注册成功！",
            //     "result": res
            // }))
        },
        Err(err) => {
            Json(MyResponce{
                status: "Bad".to_string(),
                discription: "邮箱已注册！".to_string(),
                result: err.to_string()
            })
        }
        
    }

}

#[derive(Serialize,Deserialize)]
struct LoginUser {
    login_type: LoginType,
    password: String,
}


#[derive(Serialize,Deserialize)]
enum LoginType {
    Email(String),
    PhoneNumber(String)
}



/// 使用email或phone
async fn login_action(Json(user):Json<LoginUser>,cookies:Cookies) -> Json<MyResponce> {
    
    let auth_user;

    match user.login_type {
        LoginType::Email(email) => auth_user = User::fetch_one_by_email(email).await,
        LoginType::PhoneNumber(phone_number) => auth_user = User::fetch_one_by_phone_number(phone_number).await
    }



    if let Ok(auth_user) = auth_user {
        if auth_user.password == user.password {

            if auth_user.status == "forbid"{
                return Json(MyResponce{
                    status: "Bad".to_string(),
                    discription: "你的账户已被封禁！".to_string(),
                    result: "forbid".to_string()
                })
            }

            let session_id = Uuid::new_v4().to_simple().to_string();
            let user_id = auth_user.id.to_string(); //设置用户id作为用户的标识
            // back_server::cookie::save__to_cookie(session_id.clone(), cookies);
            utils::cookie::save_user_id_to_cookie(user_id.clone(), cookies);  //将用户id放入cookie中

            let res = utils::rds::set(user_id, session_id).await;  //将用户id作为键，session_id作为值插入到redis中

            if let Err(err) = res {

                return Json(MyResponce{
                    status: "Bad".to_string(),
                    discription: "Redis出错！".to_string(),
                    result: err
                })

                
            }

            return Json(MyResponce{
                status: "Ok".to_string(),
                discription: "登录成功！".to_string(),
                result: "active".to_string()
            })
            
        }else {
            return Json(MyResponce{
                status: "Bad".to_string(),
                discription: "密码错误！".to_string(),
                result: "Ok".to_string()
            })
            
        }
    }

    Json(MyResponce{
        status: "Bad".to_string(),
        discription: "邮箱或手机号未注册！".to_string(),
        result: "Ok".to_string()
    })
    
}


async fn logout_action(cookies:Cookies) -> Json<MyResponce> {

    let user_id = utils::cookie::get_user_id_from_cookie(cookies.clone());

    if let Some(user_id) = user_id {
        cookies.remove(Cookie::named("user_id"));   //从cookie中删除user_id项
        _ = utils::rds::delete(user_id).await; //从redis上删除对应的session
    }
    Json(MyResponce{
        status:"Ok".to_string(),
        discription:"退出登录成功！".to_string(),
        result: "Ok".to_string()
    })

}

#[derive(Deserialize,Serialize)]
pub struct ResetPassword {
    old_password:String,
    new_password:String,
}

/// 重置密码
async fn reset_password(Json(rp): Json<ResetPassword>,cookies:Cookies) -> Json<MyResponce> {

    let mut user = cookie::get_user_from_cookies(cookies).await.unwrap();
    // let user = User::fetch_one_by_email(rp.email).await;

    if user.password == rp.old_password {   //验证旧密码
        // user.password = rp.new_password;
        let rs = user.update_password(rp.new_password).await;

        if let Ok(_) = rs {
            return Json(MyResponce{
                status:"Ok".to_string(),
                discription:"重置密码成功！".to_string(),
                result: "Ok".to_string()
            })
        }
    }


    Json(MyResponce{
        status:"Ok".to_string(),
        discription:"重置密码失败！".to_string(),
        result: "Bad".to_string()
    })
}

#[derive(Deserialize,Serialize)]
pub struct ResetEmail {
    email: String
}
/// 重置邮箱
async fn reset_email(Json(re):Json<ResetEmail>,cookies:Cookies) -> Json<MyResponce> {
    let mut user = cookie::get_user_from_cookies(cookies).await.unwrap();
    if let Ok(_) = user.update_email(re.email).await{
        return Json(MyResponce{
            status:"Ok".to_string(),
            discription:"重置邮箱成功！".to_string(),
            result: "Ok".to_string()
        })
    }

    Json(MyResponce{
        status:"Ok".to_string(),
        discription:"重置密码失败！".to_string(),
        result: "Bad".to_string()
    })
}


#[derive(Deserialize,Serialize)]
pub struct ResetPhoneNumber {
    phone_number: String,
}

/// 重置电话号码
async fn reset_phone_number(Json(rpn):Json<ResetPhoneNumber>,cookies:Cookies) -> Json<MyResponce> {
    let mut user = cookie::get_user_from_cookies(cookies).await.unwrap();
    if let Ok(_) = user.update_phone_number(rpn.phone_number).await{
        return Json(MyResponce{
            status:"Ok".to_string(),
            discription:"重置电话号码成功！".to_string(),
            result: "Ok".to_string()
        })
    }

    Json(MyResponce{
        status:"Ok".to_string(),
        discription:"重置电话号码失败！".to_string(),
        result: "Bad".to_string()
    })
}
#[derive(Deserialize,Serialize)]
pub struct ResetNickname {
    nickname: String,
}
async fn reset_nickname(Json(rn):Json<ResetNickname>,cookies:Cookies) -> Json<MyResponce> {
    let mut user = cookie::get_user_from_cookies(cookies).await.unwrap();
    if let Ok(_) = user.update_nickname(rn.nickname).await{
        return Json(MyResponce{
            status:"Ok".to_string(),
            discription:"重置昵称成功！".to_string(),
            result: "Ok".to_string()
        })
    }
    Json(MyResponce{
        status:"Ok".to_string(),
        discription:"重置昵称失败！".to_string(),
        result: "Bad".to_string()
    })
}
#[derive(Deserialize,Serialize)]
pub struct ResetPortrait {
    image: String,
}
async fn reset_portrait(Json(rp):Json<ResetPortrait>,cookies:Cookies)  -> Json<MyResponce> {
    let mut user = cookie::get_user_from_cookies(cookies).await.unwrap();
    if let Ok(_) = user.update_user_image(rp.image).await{
        return Json(MyResponce{
            status:"Ok".to_string(),
            discription:"重置头像成功！".to_string(),
            result: "Ok".to_string()
        })
    }
    Json(MyResponce{
        status:"Ok".to_string(),
        discription:"重置头像失败！".to_string(),
        result: "Bad".to_string()
    })
}
